package com.wwcom.darteagle.model;

public class VisitScore {
	private long id;
	private MatchPlayer matchPlayer;
	private MatchInfo matchInfo;
	private Score score; //this score is the value of the darts set by the user
	private Score validatedScore; //this score gets its darts set to 0 if they are invalid
	private boolean isFinalised;
	private int visitScore;
	private int lastLegScore;
	private int newLegScore;
	private int numVisitDartsThrown;
	private int numDartsThrown;
	private int numDartsThrownLastVisit;
	private boolean doubleInAchieved;
	private boolean trebleInAchieved;
	private boolean doubleInAchievedUnFinalised;
	private boolean trebleInAchievedUnFinalised;
	private boolean doubleInAchievedLastVisit;
	private boolean trebleInAchievedLastVisit;
		
	VisitScore() {		
		initialiseSelf();
	}

	public VisitScore( MatchInfo matchInfo, MatchPlayer matchPlayer, VisitScore lastVisit) {		
		initialiseSelf();
		this.matchPlayer= matchPlayer;
		this.matchInfo= matchInfo;
		lastLegScore= matchInfo.getLegTarget();
		newLegScore= matchInfo.getLegTarget();
		if (lastVisit != null) {
			numDartsThrownLastVisit= lastVisit.getNumDartsThrown();
			numDartsThrown= numDartsThrownLastVisit;
			lastLegScore= lastVisit.getLegScore();
			newLegScore= lastLegScore;
			doubleInAchieved= lastVisit.isDoubleInAchieved();
			trebleInAchieved= lastVisit.isTrebleInAchieved();
			doubleInAchievedLastVisit= doubleInAchieved;
			trebleInAchievedLastVisit= trebleInAchieved;
		}
	}
	

	private void initialiseSelf() {
		matchPlayer= null;
		matchInfo= null;
		isFinalised= false;
		score= new Score();
		validatedScore= new Score();
		visitScore= 0;
		lastLegScore= 0;
		newLegScore= 0;
		numVisitDartsThrown= 0;
		numDartsThrown= 0;
		numDartsThrownLastVisit= 0;
		doubleInAchieved= false;
		trebleInAchieved= false;
		doubleInAchievedLastVisit= false;
		trebleInAchievedLastVisit= false;
		id= -1;
	}
	
	//accessors
	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public boolean isFinalised() {
		return isFinalised;
	}

	public void setFinalised(boolean isFinalised) {
		this.isFinalised = isFinalised;
		if (isFinalised) {
			doubleInAchieved= doubleInAchievedUnFinalised;
			trebleInAchieved= trebleInAchievedUnFinalised;
			if (newLegScore != 0) //haven't won the leg so must have thrown 3 darts regardless of how many were entered
				numDartsThrown= numDartsThrownLastVisit + 3;
		} else {
			doubleInAchieved= doubleInAchievedLastVisit;
			trebleInAchieved= trebleInAchievedLastVisit;
			numDartsThrown= numDartsThrownLastVisit;
		}
	}

	public boolean isDoubleInAchieved() {
		return doubleInAchieved;
	}

	public boolean isTrebleInAchieved() {
		return trebleInAchieved;
	}

	public int getNumDartsThrown() {
		return numDartsThrown;
	}

	public MatchPlayer getMatchPlayer() {
		return matchPlayer;
	}

	public Score getScore() {
		return validatedScore;
	}
	
	public Score getUnvalidatedScore() {
		return score;
	}	

	public int getVisitScore() {
		return visitScore;
	}

	public int getPrevLegScore() {
		return lastLegScore;
	}

	public int getLegScore() {
		return newLegScore;
	}
	
	//This can be called many times for the same visit
	public void setScore(Score score) {
		this.score = score;
		this.validatedScore= new Score(score);
		
		//count valid darts and double/treble-in logic
		doubleInAchievedUnFinalised= doubleInAchieved;
		trebleInAchievedUnFinalised= trebleInAchieved;
		boolean doubleIn= matchInfo.isDoubleIn() && !doubleInAchievedUnFinalised;
		boolean trebleIn= matchInfo.isTrebleIn() && !trebleInAchievedUnFinalised;
		int[] dartScore= validatedScore.getDartScore();
		boolean[] isDouble= validatedScore.getIsDouble();
		boolean[] isTreble= validatedScore.getIsTreble();
		numDartsThrown= numDartsThrownLastVisit;
		numVisitDartsThrown= 0;
		for (int i= 0; i<3; i++) {

			//skip not thrown darts
			if (dartScore[i] <= -1)
				continue;
			
			//check for double and treble in satisfied
			if (trebleIn && !isTreble[i]) {
				dartScore[i]= 0;
			} else if (trebleIn && isTreble[i]) {
				trebleInAchievedUnFinalised= true;
				trebleIn= false;	
			} else if (doubleIn && !isDouble[i]) {
				dartScore[i]= 0;				
			} else if (doubleIn && isDouble[i]) {
				doubleInAchievedUnFinalised= true;
				doubleIn= false;	
			}
		}

		//subtract valid darts
		newLegScore= lastLegScore;
		visitScore= 0;
		for (int i= 0; i<3; i++) {
			
			//skip not thrown darts
			if (dartScore[i] <= -1)
				continue;
			
			//we've already won the leg before this dart
			if (newLegScore == 0) {
				dartScore[i]= 0;
				continue;
			}
			
			//add current score
			newLegScore-= dartScore[i];
			visitScore+= dartScore[i];

			numDartsThrown++;
			numVisitDartsThrown++;
			
			//bust logic
			boolean doubleOut= matchInfo.isDoubleOut();
			boolean trebleOut= matchInfo.isTrebleOut();
			if (newLegScore < 0 || (doubleOut && newLegScore > 0 && newLegScore < 2) ||
					(trebleOut && newLegScore > 0 && newLegScore < 3) ) { 
				newLegScore= lastLegScore;
				visitScore= 0;
				numDartsThrown= numDartsThrownLastVisit+3;
				numVisitDartsThrown= 3;
				for (int j= i; j<3; j++)
					dartScore[j]= 0;
				return;
			}
			
			
			//double/treble-out logic
			if (newLegScore == 0) {
				if (doubleOut && !isDouble[i] && dartScore[i] != 50) { //has to be double or bullseye
					newLegScore= lastLegScore;				
					visitScore= 0;
				} else if (trebleOut && !isTreble[i]) {
					newLegScore= lastLegScore;				
					visitScore= 0;
				}
			}
		}					
		return;			
	}
	
	//called when scores in the history have changed
	public void setLastVisit(VisitScore lastVisit) {
		numDartsThrownLastVisit= lastVisit.getNumDartsThrown();
		numDartsThrown= numDartsThrownLastVisit;
		lastLegScore= lastVisit.getLegScore();
		newLegScore= lastLegScore;
		doubleInAchieved= lastVisit.isDoubleInAchieved();
		trebleInAchieved= lastVisit.isTrebleInAchieved();
		//now update current score
		setScore(score);
	}

	public boolean get9Dart() {
		if (numDartsThrownLastVisit < 3 || numDartsThrown >= 9) {
			return false;
		}
		if (numDartsThrown >= 6) {
			String[] checkout= matchInfo.getCheckout(newLegScore,3-numVisitDartsThrown);
			if (checkout != null) {
				return true;
			} else {
				return false;
			}
		}
		int dartsRemaining= 9 - (numDartsThrown+numVisitDartsThrown);
		return (newLegScore / dartsRemaining) < 60;
	}	
	
	public String[] getCheckout() {
		return matchInfo.getCheckout(newLegScore,3-numVisitDartsThrown);
	}
			
}
